package com.aliyun.messagemgt.application.service.Impl.push.mpaas;

import com.alibaba.fastjson.JSON;
import com.aliyun.messagemgt.application.service.MsgPushChannel;
import com.aliyun.messagemgt.common.dto.send.*;
import com.aliyun.messagemgt.common.constants.MPaaSConstant;
import com.aliyun.messagemgt.common.enums.PushResultEnum;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.mpaas.model.v20190821.*;
import com.aliyuncs.profile.DefaultProfile;
import com.taobao.api.ApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 阿里mPaaS渠道消息推送
 *
 * @author byp
 * @date 2020/4/13
 * @see <a href="https://help.aliyun.com/document_detail/158619.html?spm=a2c4g.11186623.6.753.93801bbaUymcGE">阿里mpaas帮助文档</a>
 */
@Service
public class MPaaSChannel implements MsgPushChannel {

    //@Value("${ali.mpaas.regionId}")
    private String regionId;
    //@Value("${ali.mpaas.accessKeyId}")
    private String accessKeyId;
    //@Value("${ali.mpaas.accessKeySecret}")
    private String accessKeySecret;
    //@Value("${ali.mpaas.product}")
    private String product;
    //@Value("${ali.mpaas.endpoint}")
    private String endpoint;
    //@Value("${ali.mpaas.appId}")
    private String appId;
    //@Value("${ali.mpaas.workspaceId}")
    private String workspaceId;
    //@Value("${ali.mpaas.templateName}")
    private String templateName;

    private static Logger logger = LoggerFactory.getLogger(MPaaSChannel.class);

    @Override
    public Integer getChannelType() {
        return 20;
    }

    @Override
    public void push(PushChannelInfo pushChannelInfo, MsgRecordVO msgRecordVO) throws ApiException {

        //4种推送方式 1与2可以归为模板推送
        Integer sceneTemplateId = msgRecordVO.getSceneTemplateId();
        switch (sceneTemplateId) {
            case 1:
                templatePush(msgRecordVO);
                break;
            case 2:
                multiplePush(msgRecordVO);
                break;
            case 3:
                broadcastPush(msgRecordVO);
                break;
            default:
                logger.info("未知的推送类型");
                unknownPush(msgRecordVO);
        }
    }

    /**
     * 简单推送方式
     * 对一个推送 ID 推送一条消息
     *
     * @param msgRecordVO vo
     */
    private void simplePush(MsgRecordVO msgRecordVO) {
        IAcsClient client = acsClientConfig();

        //创建请求并配置参数
        PushSimpleRequest request = new PushSimpleRequest();
        request.setAppId(appId);
        request.setWorkspaceId(workspaceId);
        request.setTaskName("简单推送");
        //目标 ID 类型
        request.setDeliveryType(Long.valueOf(msgRecordVO.getDeliveryType()));
        request.setExpiredSeconds(300L);
        request.setTitle(msgRecordVO.getMsgTitle());
        //获取发送的信息
        List<MsgBody> contents = msgRecordVO.getContents();
        request.setContent(contents.get(0).getContent());

        Map<String, String> target = new HashMap<>(10);
        String msgKey = String.valueOf(System.currentTimeMillis());
        //阿里文档要求不超过10个
        List<Receiver> receiverList = msgRecordVO.getReceivers();
        //
        target.put(receiverList.get(0).getReceiverId(), msgKey);

        request.setTargetMsgkey(JSON.toJSONString(target));

        PushSimpleResponse response;
        List<MsgMiddleResult> results = msgRecordVO.getResults();
        try {
            response = client.getAcsResponse(request);
            logger.info("简单推送状态码：{},返回请求id：{}", response.getResultCode(), response.getRequestId());
            if (MPaaSConstant.CLIENT_RESPONSE_OK.equalsIgnoreCase(response.getResultCode())) {
                MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_SUCCESS.getErrorCode())
                        .setPushResultDescription(PushResultEnum.PUSH_SUCCESS.getDescription() + ",返回请求id：" + response.getRequestId())
                        .setReceivers(msgRecordVO.getReceivers());
                results.add(msgMiddleResult);
            } else {
                MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_ERROR.getErrorCode())
                        .setPushResultDescription(PushResultEnum.PUSH_ERROR.getDescription())
                        .setReceivers(msgRecordVO.getReceivers());
                results.add(msgMiddleResult);
            }
        } catch (ClientException e) {
            e.printStackTrace();
        }
    }

    /**
     * 模板推送
     * 对多个推送 ID 推送相同消息，消息通过模板创建
     *
     * @param msgRecordVO vo
     */
    private void templatePush(MsgRecordVO msgRecordVO) {
        IAcsClient client = acsClientConfig();

        PushTemplateRequest request = new PushTemplateRequest();
        request.setAppId(appId);
        request.setWorkspaceId(workspaceId);
        request.setTaskName("模板推送");
        request.setTemplateName(templateName);
        //目标 ID 类型
        request.setDeliveryType(Long.valueOf(msgRecordVO.getDeliveryType()));
        request.setExpiredSeconds(300L);

        //#msg#
        List<MsgBody> contents = msgRecordVO.getContents();
        Map<String, String> templatekv = new HashMap<>(contents.size());
        List<Receiver> receiverList;
        Map<String, String> target;
        List<MsgMiddleResult> results;
        for (MsgBody msgBody : contents) {
            templatekv.put("msg", msgBody.getContent());
            request.setTemplateKeyValue(JSON.toJSONString(templatekv));
            receiverList = msgRecordVO.getReceivers();
            target = new HashMap<>(receiverList.size());
            for (Receiver receiver : receiverList) {
                String msgKey = String.valueOf(System.currentTimeMillis());
                target.put(receiver.getReceiverId(), msgKey);
            }
            request.setTargetMsgkey(JSON.toJSONString(target));

            PushTemplateResponse response;
            results = msgRecordVO.getResults();
            try {
                response = client.getAcsResponse(request);
                logger.info("模板推送状态码：{},返回请求id：{},返回resultMessage：{}", response.getResultCode(), response.getRequestId(),response.getResultMessage());
                if (MPaaSConstant.CLIENT_RESPONSE_OK.equalsIgnoreCase(response.getResultCode())) {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_SUCCESS.getErrorCode())
                            .setPushResultDescription(PushResultEnum.PUSH_SUCCESS.getDescription() + ",返回请求id：" + response.getRequestId())
                            .setReceivers(msgRecordVO.getReceivers());
                    results.add(msgMiddleResult);
                } else {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_ERROR.getErrorCode())
                            .setPushResultDescription(response.getResultMessage())
                            .setReceivers(msgRecordVO.getReceivers());
                    results.add(msgMiddleResult);
                }
            } catch (ClientException e) {
                e.printStackTrace();
            }
        }


    }

    /**
     * 批量推送
     * 对各个推送 ID 推送不同消息，与模板推送的区别在于，每一个推送ID 可以收到内容不相同的消息
     *
     * @param msgRecordVO vo
     */
    private void multiplePush(MsgRecordVO msgRecordVO) {
        IAcsClient client = acsClientConfig();
        PushMultipleRequest request = new PushMultipleRequest();
        request.setAppId(appId);
        request.setWorkspaceId(workspaceId);
        request.setTaskName("批量推送");
        request.setTemplateName(templateName);
        //目标 ID 类型
        request.setDeliveryType(Long.valueOf(msgRecordVO.getDeliveryType()));
        request.setExpiredSeconds(300L);

        //#msg#
        List<PushMultipleRequest.TargetMsg> targetMsgs = new ArrayList<>();
        PushMultipleRequest.TargetMsg targetMsg = new PushMultipleRequest.TargetMsg();
        List<Receiver> receivers = msgRecordVO.getReceivers();
        List<MsgBody> contents = msgRecordVO.getContents();
        Map<String, String> templatekv;
        List<MsgMiddleResult> results = msgRecordVO.getResults();
        if (receivers.size() == contents.size()) {
            for (int i = 0; i < receivers.size(); i++) {
                targetMsg.setTarget(receivers.get(i).getReceiverId());
                targetMsg.setMsgKey(String.valueOf(System.currentTimeMillis()));
                templatekv = new HashMap<>(2);
                templatekv.put("msg", contents.get(i).getContent());
                targetMsg.setTemplateKeyValue(JSON.toJSONString(templatekv));

            }
            targetMsgs.add(targetMsg);
            request.setTargetMsgs(targetMsgs);

            PushMultipleResponse response;
            try {
                response = client.getAcsResponse(request);
                logger.info("批量推送状态码：{},返回请求id：{},返回resultMessage：{}", response.getResultCode(), response.getRequestId(),response.getResultMessage());
                if (MPaaSConstant.CLIENT_RESPONSE_OK.equalsIgnoreCase(response.getResultCode())) {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_SUCCESS.getErrorCode())
                            .setPushResultDescription(PushResultEnum.PUSH_SUCCESS.getDescription() + ",返回请求id：" + response.getRequestId())
                            .setReceivers(msgRecordVO.getReceivers());
                    results.add(msgMiddleResult);
                } else {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_ERROR.getErrorCode())
                            .setPushResultDescription(response.getResultMessage())
                            .setReceivers(msgRecordVO.getReceivers());
                    results.add(msgMiddleResult);
                }
            } catch (ClientException e) {
                e.printStackTrace();
            }
        } else {
            logger.info("推送用户与推送消息数量不匹配");
            MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_ERROR.getErrorCode())
                    .setPushResultDescription("推送用户与推送消息数量不匹配")
                    .setReceivers(msgRecordVO.getReceivers());
            results.add(msgMiddleResult);
        }
    }

    /**
     * 群发推送
     * 对全网设备推送相同消息，消息通过模板创建
     *
     * @param msgRecordVO vo
     */
    private void broadcastPush(MsgRecordVO msgRecordVO) {
        IAcsClient client = acsClientConfig();
        PushBroadcastRequest request = new PushBroadcastRequest();
        request.setAppId(appId);
        request.setWorkspaceId(workspaceId);
        request.setTaskName("群发推送");
        request.setTemplateName(templateName);
        //目标ID类型。此方法类型只有1-Android  2-iOS
        request.setDeliveryType(Long.valueOf(msgRecordVO.getDeliveryType()));
        request.setExpiredSeconds(300L);

        List<MsgMiddleResult> results = msgRecordVO.getResults();
        // #msg#
        List<MsgBody> contents = msgRecordVO.getContents();
        for (MsgBody msgBody : contents) {
            request.setMsgkey(String.valueOf(System.currentTimeMillis()));
            Map<String, String> templatekv = new HashMap<>(2);
            templatekv.put("msg", msgBody.getContent());
            request.setTemplateKeyValue(JSON.toJSONString(templatekv));
            PushBroadcastResponse response;
            try {
                response = client.getAcsResponse(request);
                logger.info("群发推送状态码：{},返回请求id：{},返回resultMessage：{}", response.getResultCode(), response.getRequestId(),response.getResultMessage());
                if (MPaaSConstant.CLIENT_RESPONSE_OK.equalsIgnoreCase(response.getResultCode())) {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_SUCCESS.getErrorCode())
                            .setPushResultDescription(PushResultEnum.PUSH_SUCCESS.getDescription() + ",返回请求id：" + response.getRequestId())
                            .setReceivers(msgRecordVO.getReceivers());
                    results.add(msgMiddleResult);
                } else {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_ERROR.getErrorCode())
                            .setPushResultDescription(response.getResultMessage())
                            .setReceivers(msgRecordVO.getReceivers());
                    results.add(msgMiddleResult);
                }
            } catch (ClientException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 未知的推送
     *
     * @param msgRecordVO vo
     */
    private void unknownPush(MsgRecordVO msgRecordVO) {
        List<MsgMiddleResult> results = msgRecordVO.getResults();
        MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_ERROR.getErrorCode())
                .setPushResultDescription("未知的推送类型")
                .setReceivers(msgRecordVO.getReceivers());
        results.add(msgMiddleResult);
    }

    /**
     * 配置acsClient
     *
     * @return client
     */
    private IAcsClient acsClientConfig() {
        try {
            DefaultProfile.addEndpoint(regionId, product, endpoint, "dysmsapi.aliyuncs.com");
        } catch (ClientException e) {
            e.printStackTrace();
        }
        // 创建 DefaultAcsClient 实例并初始化。 RAM 账号的AK SK
        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        return new DefaultAcsClient(profile);
    }
}
